
#ifndef __PENDINA_TRX_UTILS_H__
#define __PENDINA_TRX_UTILS_H__

#undef SLIST_ENTRY
#include "bsd_queue.h"
#pragma warning (disable: 4099)

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifndef WIN32
#define Sleep sleep
#endif

class RefCounted
{
public:
	RefCounted() : m_ref_count(0)
	{
	}

	virtual ~RefCounted()
	{
		assert(m_ref_count == 0);
	}

	void addRef() const
	{
		assert(m_ref_count >= 0);
		m_ref_count++;
	}

	void dropRef()
	{
		assert(m_ref_count > 0);
		m_ref_count--;
		if (m_ref_count == 0)
		{
			// Delete me!
			delete this;
		}
	}

private:
	mutable int	m_ref_count;
};

template<class T> class SmartPtr
{
public:
	SmartPtr(T* ptr) : m_ptr(ptr)
	{
		if (m_ptr)
		{
			((RefCounted*)m_ptr)->addRef();
		}
	}

	SmartPtr() : m_ptr(NULL) {}
	SmartPtr(const SmartPtr<T>& s) : m_ptr(s.m_ptr)
	{
		if (m_ptr)
		{
			((RefCounted*)m_ptr)->addRef();
		}
	}

	~SmartPtr()
	{
		if (m_ptr)
		{
			((RefCounted*)m_ptr)->dropRef();
		}
	}

	void	operator=(const SmartPtr<T>& s) { set_ref(s.m_ptr); }
	void	operator=(T* ptr) { set_ref(ptr); }
	bool	operator==(const SmartPtr<T>& p) const { return m_ptr == p.m_ptr; }
	bool	operator!=(const SmartPtr<T>& p) const { return m_ptr != p.m_ptr; }
	bool	operator==(T* p) const { return m_ptr == p; }
	bool	operator!=(T* p) const { return m_ptr != p; }

	T*		operator->() const { assert(m_ptr); return m_ptr; }
	T*		get_ptr() const { return m_ptr; }

private:
	void	set_ref(T* ptr)
	{
		if (ptr != m_ptr)
		{
			if (m_ptr)
			{
				((RefCounted*)m_ptr)->dropRef();
			}
			m_ptr = ptr;

			if (m_ptr)
			{
				((RefCounted*)m_ptr)->addRef();
			}
		}
	}

	T*	m_ptr;
};

class NetworkStream : public RefCounted
{
public:
	NetworkStream() : RefCounted(), mStreamData(0), mStreamDataSize(0), 
		mStreamReadPosition(0), mCurrentSize(0)
	{
		Init();
	}

	~NetworkStream()
	{
		Clear();
	}

	void WriteByte(char c)		{ WriteTemplate<char>(c);	}
	void WriteShort(short c)	{ WriteTemplate<short>(c);	}
	void WriteLong(long c)		{ WriteTemplate<long>(c);	}
	void WriteFloat(float c)	{ WriteTemplate<float>(c);	}

	char  ReadByte(void)	{ char  c = -1; ReadTemplate<char>(c);  return c; }
	short ReadShort(void)	{ short c = -1; ReadTemplate<short>(c); return c; }
	long  ReadLong(void)	{ long  c = -1; ReadTemplate<long>(c);  return c; }
	float ReadFloat(void)	{ float c = -1; ReadTemplate<float>(c); return c; }

	void WriteRaw(void *data, unsigned int length)
	{
		unsigned char* buffer = GetNewPoint(length);
		if(buffer)
		{
			//printf("%d written raw\n", length);
			memcpy(buffer, data, length);	
		}
	}

	void ReadRaw(void *buffer, unsigned int length)
	{
		if(buffer)
			Read(buffer, length);
	}

	void Seek(unsigned int pos)
	{
		assert(mStreamDataSize > pos); // cant read more than we have
		mStreamReadPosition = pos;
	}

	void Reset()
	{
		Clear();
		Init();
	}

	unsigned char* GetStreamData()
	{
		return mStreamData;
	}

	unsigned int GetStreamDataLength()
	{
		return mStreamDataSize;
	}

private:
	unsigned char *mStreamData;
	unsigned int   mStreamDataSize;
	unsigned int   mStreamReadPosition;
	unsigned int   mCurrentSize;

	unsigned char* GetNewPoint(int length)
	{
		if(mStreamDataSize + length > mCurrentSize)
		{
			mStreamData = (unsigned char *)realloc(mStreamData, mStreamDataSize + length);
			mCurrentSize = mStreamDataSize + length;
		}

		unsigned char* tempData = mStreamData + mStreamDataSize;
		mStreamDataSize += length;

		return tempData;
	}

	template<typename T> inline void WriteTemplate(T t)
	{
		Write(&t, sizeof(T));
	}

	bool Write(const void *d, int length)
	{
		unsigned char* buffer = GetNewPoint(length);
		if(buffer)
		{
			memcpy(buffer, d, length);	
		}
		return buffer != 0;		
	}

	template<typename T> inline bool ReadTemplate(T& t)
	{
		return Read(&t, sizeof(T));
	}

	bool Read(void* c, int length)
	{
		if(mStreamReadPosition+length > mStreamDataSize)
			return false;

		if(c)
			memcpy(c, &mStreamData[mStreamReadPosition], length);

		mStreamReadPosition += length;
		return true;
	}

	void Init()
	{
		mStreamData = (unsigned char *)malloc(1);
		mCurrentSize = 1;
	}

	void Clear()
	{
		if(mCurrentSize)
			free(mStreamData);

		mStreamDataSize = 0;
		mCurrentSize = 0;
	}
};

#endif
